package com.ai.faceCompare.service.impl;

/**
 * ClassName:    FaceCompareServiceImpl
 * Description:  TODO
 * Author:       yuzx
 * Date:         2025/9/7 18:41
 * Version:      1.0
 **/

import com.google.gson.Gson;
import com.ai.common.exception.ServiceException;
import com.ai.faceCompare.domain.dto.XfFaceResponseDTO;
import com.ai.faceCompare.domain.vo.FaceCompareReqVO;
import com.ai.faceCompare.domain.vo.FaceCompareRespVO;
import com.ai.faceCompare.service.IFaceCompareService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * 人脸比对服务实现类（完全复用讯飞官方示例逻辑）
 */
@Service
public class FaceCompareServiceImpl implements IFaceCompareService {

    @Autowired
    private Gson gson;

    // 从配置文件读取讯飞参数
    @Value("${iflytek.face-compare.request-url}")
    private String requestUrl;

    @Value("${iflytek.face-compare.appid}")
    private String appid;

    @Value("${iflytek.face-compare.api-secret}")
    private String apiSecret; // 对应官方示例的APISecret

    @Value("${iflytek.face-compare.api-key}")
    private String apiKey; // 对应官方示例的APIKey

    @Value("${iflytek.face-compare.service-id}")
    private String serviceId;

    /**
     * 核心逻辑：复用官方doRequest→makeRequest流程
     */
    @Override
    public FaceCompareRespVO compare(FaceCompareReqVO reqVO) {
        try {
            // 1. 构建鉴权URL
            String authUrl = assembleRequestUrl(requestUrl, apiKey, apiSecret);
            System.out.println("讯飞s67c9c78c请求-鉴权URL：" + authUrl);

            // 2. 构建请求参数
            String requestParam = buildParam(reqVO);

            // 3. 发送请求
            String xfResponse = makeRequest(authUrl, requestParam);
            System.out.println("讯飞s67c9c78c响应：" + xfResponse);

            // 4. 解析结果
            return parseXfResponse(xfResponse);
        } catch (Exception e) {
            throw new ServiceException("人脸比对失败：" + e.getMessage() + e);
        }
    }

    /**
     * 1. 完全复制讯飞官方示例的assembleRequestUrl方法（一字未改）
     */
    public static String assembleRequestUrl(String requestUrl, String apiKey, String apiSecret) {
        URL url = null;
        // 替换schema前缀
        String httpRequestUrl = requestUrl.replace("ws://", "http://").replace("wss://", "https://");
        try {
            url = new URL(httpRequestUrl);
            // 官方时间格式化（严格GMT+0，Locale.US）
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());
            System.out.println("官方示例风格 - GMT时间：" + date);

            String host = url.getHost();
            // 官方签名原文构建
            StringBuilder builder = new StringBuilder("host: ").append(host).append("\n").
                    append("date: ").append(date).append("\n").
                    append("POST ").append(url.getPath()).append(" HTTP/1.1");
            System.out.println("官方示例风格 - 签名原文：\n" + builder);

            // 官方HMAC-SHA256签名（Charset.forName("UTF-8")与官方一致）
            Charset charset = Charset.forName("UTF-8");
            Mac mac = Mac.getInstance("hmacsha256");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
            String sha = Base64.getEncoder().encodeToString(hexDigits);
            System.out.println("官方示例风格 - HMAC-SHA256签名：" + sha);

            // 官方Authorization构建（双引号、逗号格式严格）
            String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                    apiKey, "hmac-sha256", "host date request-line", sha);
            System.out.println("官方示例风格 - Authorization：" + authorization);

            // 官方Base64编码（与官方一致）
            String authBase = Base64.getEncoder().encodeToString(authorization.getBytes(charset));
            System.out.println("官方示例风格 - Authorization(Base64)：" + authBase);

            // 官方URL拼接（URLEncoder编码，显式UTF-8）
            return String.format("%s?authorization=%s&host=%s&date=%s",
                    requestUrl,
                    URLEncoder.encode(authBase, "UTF-8"),
                    URLEncoder.encode(host, "UTF-8"),
                    URLEncoder.encode(date, "UTF-8")
            );
        } catch (Exception e) {
            throw new RuntimeException("官方示例风格 - 构建鉴权URL失败：" + e.getMessage());
        }
    }

    /**
     * 2. 替换本地图片为前端Base64
     */
    private String buildParam(FaceCompareReqVO reqVO) {
        // 完全复用官方JSON构建逻辑
        com.google.gson.JsonObject req = new com.google.gson.JsonObject();

        // 平台参数（与官方一致）
        com.google.gson.JsonObject header = new com.google.gson.JsonObject();
        header.addProperty("app_id", appid);
        header.addProperty("status", 3);
        req.add("header", header);

        // 功能参数（与官方一致）
        com.google.gson.JsonObject parameter = new com.google.gson.JsonObject();
        com.google.gson.JsonObject inputAcp = new com.google.gson.JsonObject();
        com.google.gson.JsonObject result = new com.google.gson.JsonObject();
        inputAcp.addProperty("service_kind", "face_compare");
        result.addProperty("encoding", "utf8");
        result.addProperty("compress", "raw");
        result.addProperty("format", "json");
        inputAcp.add("face_compare_result", result);
        parameter.add(serviceId, inputAcp);
        req.add("parameter", parameter);

        // 请求数据（关键：替换官方本地图片读取为前端Base64）
        com.google.gson.JsonObject payload = new com.google.gson.JsonObject();
        // 第一张图片（前端传递的Base64，编码与前端一致）
        com.google.gson.JsonObject payloadImage1 = new com.google.gson.JsonObject();
        payloadImage1.addProperty("encoding", reqVO.getImageEncoding()); // 前端传递的编码
        payloadImage1.addProperty("status", 3);
        payloadImage1.addProperty("image", reqVO.getImage1()); // 前端Base64（无前缀）
        payload.add("input1", payloadImage1);
        // 第二张图片（与第一张一致）
        com.google.gson.JsonObject payloadImage2 = new com.google.gson.JsonObject();
        payloadImage2.addProperty("encoding", reqVO.getImageEncoding());
        payloadImage2.addProperty("status", 3);
        payloadImage2.addProperty("image", reqVO.getImage2());
        payload.add("input2", payloadImage2);
        req.add("payload", payload);

        return req.toString();
    }

    /**
     * 3. 完全复制讯飞官方示例的makeRequest方法（
     */
    private String makeRequest(String authUrl, String requestParam) throws Exception {
        URL realUrl = new URL(authUrl);
        HttpURLConnection httpURLConnection = (HttpURLConnection) realUrl.openConnection();

        // 官方请求配置（完全一致）
        httpURLConnection.setDoInput(true);
        httpURLConnection.setDoOutput(true);
        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setRequestProperty("Content-type", "application/json"); // 仅保留官方必要头

        // 发送请求参数
        OutputStream out = httpURLConnection.getOutputStream();
        out.write(requestParam.getBytes()); // 与官方一致：直接用默认编码（UTF-8）
        out.flush();
        out.close();

        // 读取响应
        InputStream is = null;
        try {
            is = httpURLConnection.getInputStream();
            System.out.println("官方示例风格 - 请求状态码：" + httpURLConnection.getResponseCode());
        } catch (Exception e) {
            // 读取错误流
            is = httpURLConnection.getErrorStream();
            if (is != null) {
                byte[] errorResp = inputStream2ByteArray(is);
                String errorMsg = new String(errorResp);
                throw new Exception("官方示例风格 - 请求错误：状态码=" + httpURLConnection.getResponseCode() +
                        "，错误信息=" + httpURLConnection.getResponseMessage() + "，响应体=" + errorMsg);
            } else {
                throw new Exception("官方示例风格 - 请求错误：无错误流，状态码=" + httpURLConnection.getResponseCode());
            }
        }

        // 读取正常响应
        byte[] resp = inputStream2ByteArray(is);
        is.close();
        return new String(resp);
    }

    /**
     * 复用官方FileUtil的inputStream2ByteArray方法
     */
    private byte[] inputStream2ByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }

    /**
     * 结果解析逻辑（匹配讯飞官方字段）
     */
    private FaceCompareRespVO parseXfResponse(String xfResponse) {
        // 1. 解析整体响应体（Gson now能正确识别face_compare_result）
        XfFaceResponseDTO.ResponseBody responseBody = gson.fromJson(xfResponse, XfFaceResponseDTO.ResponseBody.class);
        XfFaceResponseDTO.XfResponseHeader header = responseBody.getHeader();

        // 2. 校验讯飞会话状态（code=0表示会话成功）
        if (header.getCode() != 0) {
            throw new ServiceException(String.format(
                    "讯飞会话错误：code=%d，msg=%s，sid=%s",
                    header.getCode(), header.getMessage(), header.getSid()
            ));
        }

        // 3. 获取人脸比对结果（现在能正确拿到face_compare_result，不再为null）
        XfFaceResponseDTO.XfResponsePayload payload = responseBody.getPayload();
        if (payload == null) {
            throw new ServiceException("讯飞未返回payload数据，sid：" + header.getSid());
        }

        XfFaceResponseDTO.XfResponsePayload.XfFaceCompareResult faceCompareResult = payload.getFaceCompareResult();
        if (faceCompareResult == null || faceCompareResult.getText() == null || faceCompareResult.getText().isEmpty()) {
            throw new ServiceException("讯飞未返回人脸比对结果text，sid：" + header.getSid());
        }

        // 4. Base64解码text字段（官方文档：text是Base64编码的JSON）
        String textBase64 = faceCompareResult.getText();
        String textDecoded;
        try {
            // 用Java原生Base64解码（与官方示例一致）
            textDecoded = new String(Base64.getDecoder().decode(textBase64), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new ServiceException("人脸比对结果text Base64解码失败，sid：" + header.getSid()+e);
        }
        System.out.println("【讯飞解析】text解码后：" + textDecoded); // 调试用：确认解码结果

        // 5. 解析解码后的比对结果（字段名：ret=状态，score=相似度）
        XfFaceResponseDTO.XfCompareResultText compareResult = gson.fromJson(textDecoded, XfFaceResponseDTO.XfCompareResultText.class);
        if (compareResult == null) {
            throw new ServiceException("人脸比对结果解析失败，sid：" + header.getSid());
        }

        // 6. 校验比对业务状态（ret=0表示比对成功，官方文档定义）
        if (compareResult.getRet() != 0) {
            throw new ServiceException(String.format(
                    "人脸比对业务错误：ret=%d，error_msg=%s，sid：%s",
                    compareResult.getRet(), compareResult.getError_msg(), header.getSid()
            ));
        }

        // 7. 组装返回给前端的结果（用score字段，与官方一致）
        FaceCompareRespVO respVO = new FaceCompareRespVO();
        respVO.setScore(compareResult.getScore()); // 相似度（官方字段：score）
        respVO.setSid(header.getSid()); // 讯飞会话ID
        respVO.setRawText(compareResult); // 原始解析结果（前端展示用）

        return respVO;
    }
}